﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Win32;
using SecureCommander.Helper;
using System.IO;
using SecureCommander.Core.SecurityManager;
using SecureCommander.Core.UserManagement;
using System.Security.Cryptography;
using Ionic.Zip;

namespace SecureCommander.GUI
{
    /// <summary>
    /// Interaction logic for FormDecrypt.xaml
    /// </summary>
    public partial class FormDecrypt : Window
    {

        public string OutputDir { get; set; }
        public string EncryptedFile { get; set; }
        public UserInfo User { get; set; }
        public string Passphrase { get; set; }

        public FormDecrypt()
        {
            InitializeComponent();
        }

        private void btnBrowseEncryptedFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog opendiasrc = new OpenFileDialog();
            if (opendiasrc.ShowDialog().Value)
            {
                txtEncryptedFile.Text = opendiasrc.FileName;
                EncryptedFile = opendiasrc.FileName;
                txtOutput.Text = txtEncryptedFile.Text.Substring(0, txtEncryptedFile.Text.LastIndexOf("\\")+1);
                OutputDir = txtOutput.Text;
            }
        }

        private void btnBrowseOutput_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog frm = new System.Windows.Forms.FolderBrowserDialog();
            if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtOutput.Text = frm.SelectedPath;
                OutputDir = txtOutput.Text;
            }
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            if (txtEncryptedFile.Text == "" || txtOutput.Text == "")
            {
                FileHelper.ShowMessage("Please specify encrypted file and output directory!", MessageBoxImage.Warning);
                return;
            }
            OutputDir = txtOutput.Text;
            if (!OutputDir.EndsWith("\\"))
            {
                OutputDir += "\\";
            }
            EncryptedFile = txtEncryptedFile.Text;

            Decrypt();

            e.Handled = true;
            DialogResult = true;
        }

        private void Decrypt()
        {
            try
            {
                FileStream filestream = new FileStream(EncryptedFile, FileMode.Open, FileAccess.Read);
                byte[] EnBuffer = new byte[filestream.Length];
                EnBuffer = File.ReadAllBytes(EncryptedFile);
                filestream.Close();

                string EnFile = OutputDir + "EnFile.en";
                /**********/
                byte[] Key;
                byte[] Iv;
                byte AlgByte;
                byte ModeByte;
                byte PadByte;
                byte Zip;
                try
                {
                    RijndaelAlgorithm Rij = new RijndaelAlgorithm();
                    string Privatekey = Rij.Decrypt(User.Privatekey, Passphrase);
                    //Privatekey = "<RSAKeyValue><Modulus>te+iq+1lqiYDI05ptthPBnE75Oe+gCNUN8VwyrcSI/PSyxjZhFvm1few/gQkAeb0sDbAcJy+22ikLJ5hyMCV2/dJUrks+XMBFfGPZnTiIk8=</Modulus><Exponent>AQAB</Exponent><P>2jKKbWSikdYIshYKlhvyTpzIiMlsOCqElXvFtzeznCUp8VgyJeTyZw==</P><Q>1XTWOpYX6P0zmsfEb4qTMRV8nPfIzZTaAWSstDA6cGTHAbsuE9pv2Q==</Q><DP>eyWjMvJlPmHKLph6CRZkvzGFjI4B4gE9KxDcGff6Ctp+vZPFWdXJaQ==</DP><DQ>JLXGTicYD5rUMC9hCinT7KIcX0aCA1ExOQIebZLJyiCa1SJi50ku6Q==</DQ><InverseQ>olqs1QGINUdB9k3SWhaUDIW3CMpUnn8MkBTduMEcQp2ko1PJVBkVAg==</InverseQ><D>l7OnGmCqosNrXmclsraOvjpwzJ+HsuTCdnaFZCJeV+gY3gxsYvcWc+9VRQbxzIIXKsXcmQyZ2BiSjIWCr2vdKVHYYR+3q5fWxNwFolRw12E=</D></RSAKeyValue>";
                    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();

                    rsaProvider.FromXmlString(Privatekey);
                    int keysize = rsaProvider.KeySize / 8;

                    byte[] KeyByte = new byte[keysize];
                    for (int i = 0; i < keysize; i++)
                        KeyByte[i] = EnBuffer[EnBuffer.Length - (2 * keysize + 4) + i];

                    byte[] IvByte = new byte[keysize];
                    for (int i = 0; i < keysize; i++)
                        IvByte[i] = EnBuffer[EnBuffer.Length - (keysize + 4) + i];

                    AlgByte = EnBuffer[EnBuffer.Length - 4];
                    ModeByte = EnBuffer[EnBuffer.Length - 3];
                    PadByte = EnBuffer[EnBuffer.Length - 2];
                    Zip = EnBuffer[EnBuffer.Length - 1];


                    filestream = new FileStream(EnFile, FileMode.Create, FileAccess.Write);
                    filestream.Write(EnBuffer, 0, EnBuffer.Length - (2 * keysize + 4));
                    filestream.Close();


                    Key = rsaProvider.Decrypt(KeyByte, false);
                    Iv = rsaProvider.Decrypt(IvByte, false);
                }
                catch (Exception ex)
                {
                    FileHelper.ShowMessage(ex.Message, MessageBoxImage.Error);
                    if (File.Exists(EnFile))
                    {
                        File.Delete(EnFile);
                    }
                    return;
                }

                PaddingMode Pad = PaddingMode.None;
                switch (PadByte)
                {
                    case 0:
                        Pad = PaddingMode.ANSIX923;
                        break;
                    case 1:
                        Pad = PaddingMode.PKCS7;
                        break;
                    case 2:
                        Pad = PaddingMode.ISO10126;
                        break;
                }

                CipherMode Cipher = CipherMode.ECB;
                switch (ModeByte)
                {
                    case 0:                        
                        Cipher = CipherMode.CBC;
                        break;
                    case 1:
                        Cipher = CipherMode.CFB;
                        break;
                    case 2:                        
                        Cipher = CipherMode.CTS;
                        break;
                    case 3:
                        Cipher = CipherMode.ECB;       
                        break;
                    case 4:
                        Cipher = CipherMode.OFB;
                        break;
                }

                string PathFileOutTmp = OutputDir + "DecryptFile.zip";
                switch (AlgByte)
                {
                    case 0:
                        DesAlgorithm DesAgl = new DesAlgorithm(Pad, Cipher, Key, Iv);
                        if (!DesAgl.DecryptFile(EnFile, PathFileOutTmp))
                        {
                            MessageBox.Show("Decrypt fail!! Algorithm not support this padding/cipher");
                            return;
                        }

                        break;
                    case 1:
                        TripleDesAlgorithm TriplaDesAgl = new TripleDesAlgorithm(Pad, Cipher, Key, Iv);
                        if (!TriplaDesAgl.DecryptFile(EnFile, PathFileOutTmp))
                        {
                            MessageBox.Show("Decrypt fail!! Algorithm not support this padding/cipher");
                            return;
                        }
                        break;
                    case 2:
                        RijndaelAlgorithm RijAgl = new RijndaelAlgorithm(Pad, Cipher, Key, Iv);
                        if (!RijAgl.DecryptFile(EnFile, PathFileOutTmp))
                        {
                            MessageBox.Show("Decrypt fail!! Algorithm not support this padding/cipher");
                            return;
                        }
                        break;
                    case 3:
                        RC2Algorithm Rc2Agl = new RC2Algorithm(Pad, Cipher, Key, Iv);
                        if (!Rc2Agl.DecryptFile(EnFile, PathFileOutTmp))
                        {
                            MessageBox.Show("Decrypt fail!! Algorithm not support this padding/cipher");
                            return;
                        }
                        break;
                }
                if (Zip != 1)
                {
                    ZipFile zip = new ZipFile(PathFileOutTmp);
                    foreach (ZipEntry entry in zip)
                    {
                        entry.Extract(OutputDir, ExtractExistingFileAction.OverwriteSilently);
                    }
                    zip.Dispose();
                    File.Delete(PathFileOutTmp);
                }

                if (File.Exists(EnFile))
                {
                    File.Delete(EnFile);
                }
            }
            catch (Exception ex)
            {
                FileHelper.ShowMessage(ex.Message, MessageBoxImage.Error);
                return;
            }
            FileHelper.ShowMessage("Decrypt successfully", MessageBoxImage.Information);
        }
    }
}
